package com.szxx.suit.threestraight;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.springframework.stereotype.Component;

import com.szxx.constant.DdzCardTypes;
import com.szxx.constant.DdzCardConstant;
import com.szxx.domain.Card;
import com.szxx.domain.Cards;
import com.szxx.domain.DdzCard;
import com.szxx.suit.AbstractSuitTerm;
import com.szxx.suit.AbstractSuitType;
import com.szxx.suit.DdzAnalysisResult;
import com.szxx.suit.DdzSuitAnalyzer;
import com.szxx.suit.DdzTypeUtil;

/**
 * 三顺牌型 <br>
 *
 * @author Ambrose
 */
@Component
public class ThreeStraightTypeAnalyzer extends DdzSuitAnalyzer {

	@Override
	public AbstractSuitType getSuitType() {
		return DdzCardTypes.THREE_STRAIGHT;
	}

	/** 关键数量 */
	private static int LIMIT_SIZE = 6;
	
	/** 关键数量 */
	public static int TUPLE_SIZE = 3;
	
	@Override
	public boolean doCheckRule(Cards cards, AbstractSuitTerm term, DdzAnalysisResult result) {
		if (result.getCardNum() >= LIMIT_SIZE 
				&& result.getCardNum() % TUPLE_SIZE == 0) { // 三顺至少六张且数量为三的倍数
			if (result.isAllCardLazi()) { // 都是癞子
				return false;
			}  else {
				if (result.getNoneLaziValueCounter().hasJoker()) { // 非赖部分有王
					return false;
				}
				if (result.getNoneLaziValueCounter().getValueCount(DdzCardConstant.NUMBER_2_VALUE) > 0) { // 非赖部分有2
					return false;
				}
				List<Integer> allNumber = result.getNoneLaziValueCounter().getAllValues();
				for (Integer number : allNumber) { // 全是单张，对子，三张
					if (result.getNoneLaziValueCounter().getValueCount(number) > TUPLE_SIZE) {
						return false;
					}
				}
				int tupleNum = result.getCardNum() / TUPLE_SIZE; // 分析有几组牌，三顺中一对算做一组
				// 遍历寻找所有可能的顺子
				for (int valueTemp = DdzCardConstant.NUMBER_2_VALUE - 1 // 从A开始
						; valueTemp >= DdzCardConstant.NUMBER_3_VALUE + (tupleNum - 1); valueTemp--) {
					if (DdzTypeUtil.ensureStaight(valueTemp, TUPLE_SIZE, TUPLE_SIZE, cards, term, result)) {
						return true;
					}
				}
				return false;
			}
		} else {
			return false;
		}
	}
	
	@Override
	protected List<Cards> doAnalysizeLaizi(Cards cards, AbstractSuitTerm term, boolean onlyMaxValue) {
		List<Cards> cardsResult = new LinkedList<Cards>();
		DdzAnalysisResult result = (DdzAnalysisResult) cards.getResult();
		List<Card> laiziCardList = new ArrayList<Card>(cards.subList(result.getCardNum() - result.getLaziCardNum(), result.getCardNum()));
		int tupleNum = result.getCardNum() / TUPLE_SIZE; // 分析有几组牌，顺子中单张也算做一组
		// 遍历寻找所有可能的顺子
		for (int beginValueTemp = DdzCardConstant.NUMBER_2_VALUE - 1 // 从A开始
				; beginValueTemp >= DdzCardConstant.NUMBER_3_VALUE + (tupleNum - 1); beginValueTemp--) {
			if (DdzTypeUtil.ensureStaight(beginValueTemp, TUPLE_SIZE, TUPLE_SIZE, cards, term, result)) {
				int laiziCardIndex = 0;
				for (int valueTemp = beginValueTemp; valueTemp > beginValueTemp - tupleNum; valueTemp--) { // 从大到小
					int valueTempNum = result.getNoneLaziValueCounter().getValueCount(valueTemp);
					int needLaiziCardNum = TUPLE_SIZE - valueTempNum;
					for (int i = 0; i < needLaiziCardNum; i++) {
						((DdzCard) laiziCardList.get(laiziCardIndex++)).changeCard(valueTemp);
					}
				}
				Cards cardsCopy = cards.clone();
				analysize(cardsCopy, term);
				cardsResult.add(cardsCopy);
				if (onlyMaxValue) {
					break; // 取完最大一组就跳出
				}
			}
		}
		return cardsResult;
	}
	
	@Override
	protected boolean containsPossibleCards(Cards handCards, AbstractSuitTerm term) {
		DdzAnalysisResult result = (DdzAnalysisResult) handCards.getResult();
		if (result.getCardNum() - result.getJokerCardNum() < LIMIT_SIZE) { // 张数不够
			return false;
		}
		// 遍历寻找所有可能的顺子
		for (int beginValueTemp = DdzCardConstant.NUMBER_2_VALUE - 1 // 从A开始
				; beginValueTemp >= DdzCardConstant.NUMBER_3_VALUE + LIMIT_SIZE / TUPLE_SIZE - 1; beginValueTemp--) {
			if (DdzTypeUtil.ensureTupleStaightDesc(
					beginValueTemp, LIMIT_SIZE / TUPLE_SIZE, TUPLE_SIZE, handCards, term, result)) { // 最低标准顺一下
				return true;
			}
		}
		return false;
	}
	
	/** 最多使用癞子的数量 */
	private static int MAX_USE_LAIZI_CARD_NUM = 8;
	
	/** 防重复判定的比例值 参照 int key = tupleNum * TUPLE_WEIGHT + beginValueTemp; */
	private static int TUPLE_WEIGHT = 1000000;
	
	/** 癞子权重，区分癞子变成的5 和 原本就是5 */
	private static int LAIZI_WEIGHT = 1000;
	
	@Override
	protected List<Cards> doListPossibleCards(Cards handCards, AbstractSuitTerm term) {
		List<Cards> cardsResult = new LinkedList<Cards>();
		// 非癞子部分
		DdzAnalysisResult result = (DdzAnalysisResult) handCards.getResult();
		List<Card> noneLaiziCardList = handCards.subList(0, result.getNoneCardNum());
		Cards noneLaiziCards = DdzTypeUtil.createCardsCopy(noneLaiziCardList);
		noneLaiziCards.setResult(handCards.getResult().clone());
		// 癞子部分
		List<Card> laiziCardList = handCards.subList(result.getNoneCardNum(), result.getCardNum());
		Cards laiziCards = DdzTypeUtil.createCardsCopy(laiziCardList);
		laiziCards.setResult(handCards.getResult().clone());
		
		int laiziCardNum = result.getLaziCardNum();
		int maxUseLaiziCardNum = MAX_USE_LAIZI_CARD_NUM < laiziCardNum ? MAX_USE_LAIZI_CARD_NUM : laiziCardNum;
		Set<Integer> exsitKeys = new HashSet<Integer>();
		for (int useLaiziCardNum = 0; useLaiziCardNum <= maxUseLaiziCardNum; useLaiziCardNum++) { // 补几张癞子
			List<Card> useLaiziCardList = DdzTypeUtil.cloneSublistedCards(laiziCards, 0, useLaiziCardNum); // 补癞子
			Collections.reverse(useLaiziCardList); // 因为这里是倒序赋值，避免 把点数小的癞子牌赋成大值又把点数大的癞子牌赋成小值 的疑惑
			Cards modelCards = DdzTypeUtil.cloneCardsAndAddCardList(noneLaiziCards, useLaiziCardList); // 常规牌补上癞子
			DdzAnalysisResult modelResult = (DdzAnalysisResult) modelCards.getResult();
			modelResult.collectNumber(modelCards, term); // 重新获取下点值
			// 从5顺开始找 10.JQK1 找完找 9.10.J.Q.K.1 在找 8.9.10.J.Q.K.1 
			for (int tupleNum = LIMIT_SIZE / TUPLE_SIZE; tupleNum <= modelResult.getCardNum() / TUPLE_SIZE; tupleNum++) {
				LinkedList<Cards> partLenResult = new LinkedList<Cards>(); // 部分长度的结果 
				// 遍历寻找所有可能的顺子  10.J.Q.K.1 找完找 9.10.J.Q.K 在找 8.9.10.J.Q
				for (int beginValueTemp = DdzCardConstant.NUMBER_2_VALUE - 1 // 从A开始
						; beginValueTemp >= DdzCardConstant.NUMBER_3_VALUE + tupleNum - 1; beginValueTemp--) {
					int laiziCardIndex = 0;
					int straightKey = tupleNum * TUPLE_WEIGHT + beginValueTemp;
					if (!exsitKeys.contains(straightKey) // 每种顺子仅判定一次
							&& DdzTypeUtil.ensureTupleStaightDesc(beginValueTemp, tupleNum, TUPLE_SIZE, modelCards, term, modelResult)) {
						exsitKeys.add(straightKey);
						Cards straightCards = new Cards();
						for (int valueTemp = beginValueTemp; valueTemp > beginValueTemp - tupleNum; valueTemp--) { // 从大到小
							int valueTempNum = modelResult.getNoneLaziValueCounter().getValueCount(valueTemp);
							if (valueTempNum >= TUPLE_SIZE) {
								straightCards.addCards(DdzTypeUtil.cloneObtainedCards(modelCards, valueTemp, TUPLE_SIZE));
							} else {
								straightCards.addCards(DdzTypeUtil.cloneObtainedCards(modelCards, valueTemp, valueTempNum));
								int needLaiziCardNum = TUPLE_SIZE - valueTempNum;
								for (int i = 0; i < needLaiziCardNum; i++) { // 用了癞子才加上，不会任意补全（癞子不会去替代玩家已有的顺子中的元素）
									DdzCard laiziCardCopy = (DdzCard) useLaiziCardList.get(laiziCardIndex++).clone();
									laiziCardCopy.changeCard(valueTemp);
									straightCards.addCard(laiziCardCopy);
								}
							}
						}
						int laiziNumKey = 0;
						for (Card card : straightCards) {
							if (((DdzCard)card).isLazi()) { // 癞子权重，区分癞子变成的5 和 原本就是5
								laiziNumKey += LAIZI_WEIGHT;
							} else {
								laiziNumKey += card.getValue();
							}
						}
						if (!exsitKeys.contains(laiziNumKey) // 保证癞子不会变形 比如  **10** 和 10**** 只出现一次最大的提牌
								&& match(straightCards, term)) {
							exsitKeys.add(laiziNumKey);
							analysize(straightCards, term);
							partLenResult.addFirst(straightCards); // 这里倒序加入，保证从小到大
						}
					}
				}
				cardsResult.addAll(partLenResult);
			}
		}
		return cardsResult;
	}
	
}
